package com.nineshadow.games.netty.socket;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;


/**
 * <p>
 * netty socket 服务端启动类
 * </p>
 *
 * @author bingjun zhang
 * @since 2018/7/31
 */
@Slf4j
@Component
public class EchoServer {

    //    private static final int PORT = 18888;
    private static final int PORT = 10087;
    /**
     * 读超时（秒）
     */
    private static final int READ_IDEL_TIME_OUT = 30;
    /**
     * 写超时（秒）
     */
    private static final int WRITE_IDEL_TIME_OUT = 40;
    /**
     * 所有超时时间（秒）
     */
    private static final int ALL_IDEL_TIME_OUT = 50;
    private static ChannelFuture f;
    /**
     * netty 线程池
     */
    private static EventLoopGroup bossGroup;
    private static EventLoopGroup workerGroup;

    public static void run() {

        bossGroup = new NioEventLoopGroup();
        workerGroup = new NioEventLoopGroup();

        try {
            // (1)服务器辅助启动类配置
            ServerBootstrap b = new ServerBootstrap();
            //(2) 加入线程组
            b.group(bossGroup, workerGroup)
                    // 设置非阻塞,用它来建立新accept的连接,用于构造serversocketchannel的工厂类
                    .channel(NioServerSocketChannel.class)
                    //(3) log 支持
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChildChannelHandler())
                    // (4)设置tcp缓冲区
                    .option(ChannelOption.SO_BACKLOG, 2048)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            // (5)绑定端口 同步等待绑定成功
            log.info("*********netty 启动成功 端口 " + PORT + " *********");
            //(7) 监听端口
            f = b.bind(PORT).sync();
        } catch (Exception e) {
            log.info("*********netty 启动失败 端口 " + PORT + " *********");
            log.error("netty启动失败", e);
            try {
                f.channel().closeFuture().sync();
            } catch (InterruptedException e1) {
                log.error("关闭netty", e);
            }
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    /**
     * EchoServer 销毁
     */
    public static void destory() {
        log.info("*********EchoServer 销毁 *********");
        try {
            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        workerGroup.shutdownGracefully();
        bossGroup.shutdownGracefully();

    }

    /**
     * 网络事件处理器
     */
    private static class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            // (6)添加自定义协议的编解码工具
            //编码器
            ch.pipeline().addLast(new SmartCarEncoder());
            //解码器
            ch.pipeline().addLast(new SmartCarDecoder());
            // 心跳处理
            ch.pipeline().addLast(new IdleStateHandler(READ_IDEL_TIME_OUT,
                    WRITE_IDEL_TIME_OUT, ALL_IDEL_TIME_OUT, TimeUnit.SECONDS));
            // 处理网络IO
            ch.pipeline().addLast(new EchoServerHandler());
        }
    }
}
